#include "w6100_init.h"
#include "print_rtt.h"

/* 1. 为互斥量准备的静态内存 */
static StaticSemaphore_t w6100_op_xMutexBuffer;
/* 2. 全局句柄，方便其他文件引用 */
SemaphoreHandle_t w6100_op_xStaticMutex;

int vCreateW6100StaticMutex(void)
{
  /* 3. 创建静态互斥量 */
  w6100_op_xStaticMutex = xSemaphoreCreateMutexStatic(&w6100_op_xMutexBuffer);
  configASSERT(w6100_op_xStaticMutex != NULL); /* 创建失败会停在这里 */
  return 0;
}

uint16_t ATOI(char *str, uint16_t base)
{
  unsigned int num = 0;
  while (*str != 0)
    num = num * base + C2D(*str++);
  return num;
}

uint32_t ATOI32(char *str, uint16_t base)
{
  uint32_t num = 0;
  while (*str != 0)
    num = num * base + C2D(*str++);
  return num;
}

void itoa(uint16_t n, uint8_t str[5], uint8_t len)
{

  uint8_t i = len - 1;

  memset(str, 0x20, len);
  do
  {
    str[i--] = n % 10 + '0';

  } while ((n /= 10) > 0);

  return;
}

int ValidATOI(char *str, int base, int *ret)
{
  int c;
  char *tstr = str;
  if (str == 0 || *str == '\0')
    return 0;
  while (*tstr != '\0')
  {
    c = C2D(*tstr);
    if (c >= 0 && c < base)
      tstr++;
    else
      return 0;
  }

  *ret = ATOI(str, base);
  return 1;
}

void replacetochar(char *str, char oldchar, char newchar)
{
  int x;
  for (x = 0; str[x]; x++)
    if (str[x] == oldchar)
      str[x] = newchar;
}

char C2D(uint8_t c)
{
  if (c >= '0' && c <= '9')
    return c - '0';
  if (c >= 'a' && c <= 'f')
    return 10 + c - 'a';
  if (c >= 'A' && c <= 'F')
    return 10 + c - 'A';

  return (char)c;
}

uint16_t swaps(uint16_t i)
{
  uint16_t ret = 0;
  ret = (i & 0xFF) << 8;
  ret |= ((i >> 8) & 0xFF);
  return ret;
}

uint32_t swapl(uint32_t l)
{
  uint32_t ret = 0;
  ret = (l & 0xFF) << 24;
  ret |= ((l >> 8) & 0xFF) << 16;
  ret |= ((l >> 16) & 0xFF) << 8;
  ret |= ((l >> 24) & 0xFF);
  return ret;
}

void inet_addr_(unsigned char *addr, unsigned char *ip)
{
  int i;
  //	u_long inetaddr = 0;
  char taddr[30];
  char *nexttok;
  char num;
  strcpy(taddr, (char *)addr);

  nexttok = taddr;
  for (i = 0; i < 4; i++)
  {
    nexttok = strtok(nexttok, ".");
    if (nexttok[0] == '0' && nexttok[1] == 'x')
      num = ATOI(nexttok + 2, 0x10);
    else
      num = ATOI(nexttok, 10);

    ip[i] = num;
    nexttok = NULL;
  }
}
/**
@brief	Convert 32bit Address(Host Ordering) into Dotted Decimal Format
@return 	a char pointer to a static buffer containing the text address in standard ".'' notation. Otherwise, it returns NULL.
*/
char *inet_ntoa(
    unsigned long addr /**< Pointer variable to store converted value(INPUT) */
)
{
  static char addr_str[32];
  memset(addr_str, 0, 32);
  sprintf(addr_str, "%d.%d.%d.%d", (int)(addr >> 24 & 0xFF), (int)(addr >> 16 & 0xFF), (int)(addr >> 8 & 0xFF), (int)(addr & 0xFF));
  return addr_str;
}

char *inet_ntoa_pad(unsigned long addr)
{
  static char addr_str[16];
  memset(addr_str, 0, 16);
  printf(addr_str, "%03d.%03d.%03d.%03d", (int)(addr >> 24 & 0xFF), (int)(addr >> 16 & 0xFF), (int)(addr >> 8 & 0xFF), (int)(addr & 0xFF));
  return addr_str;
}

/**
@brief	Verify dotted notation IP address string
@return 	success - 1, fail - 0
*/
char VerifyIPAddress_orig(
    char *src /**< pointer to IP address string */
)
{
  int i;
  int tnum;
  char tsrc[50];
  char *tok = tsrc;

  strcpy(tsrc, src);

  for (i = 0; i < 4; i++)
  {
    tok = strtok(tok, ".");
    if (!tok)
      return 0;
    if (tok[0] == '0' && tok[1] == 'x')
    {
      if (!ValidATOI(tok + 2, 0x10, &tnum))
        return 0;
    }
    else if (!ValidATOI(tok, 10, &tnum))
      return 0;

    if (tnum < 0 || tnum > 255)
      return 0;
    tok = NULL;
  }
  return 1;
}

char VerifyIPAddress(char *src, uint8_t *ip)
{
  int i;
  int tnum;
  char tsrc[50];
  char *tok = tsrc;

  strcpy(tsrc, src);

  for (i = 0; i < 4; i++)
  {
    tok = strtok(tok, ".");
    if (!tok)
      return 0;
    if (tok[0] == '0' && tok[1] == 'x')
    {
      if (!ValidATOI(tok + 2, 0x10, &tnum))
        return 0;
    }
    else if (!ValidATOI(tok, 10, &tnum))
      return 0;

    ip[i] = tnum;

    if (tnum < 0 || tnum > 255)
      return 0;
    tok = NULL;
  }
  return 1;
}
/**
@brief	Output destination IP address of appropriate channel
@return 	32bit destination address (Host Ordering)
*/
#if 0
unsigned long GetDestAddr(
	SOCKET s	/**< Channel number which try to get destination IP Address */
	)
{
	u_long addr=0;
	int i = 0;
	for(i=0; i < 4; i++)
	{
		addr <<=8;
		addr +=  WIZCHIP_READ(W6100_Sn_DIPR0(s)+i);
	}
	return addr;
}
#endif
/**
@brief	Output destination port number of appropriate channel
@return 	16bit destination port number
*/
#if 0
unsigned int GetDestPort(
	SOCKET s	/**< Channel number which try to get destination port */
	)
{
	u_int port;
	port = ((u_int)  WIZCHIP_READ(W6100_Sn_DPORT0(s))) & 0x00FF;
	port <<= 8;
	port += ((u_int)  WIZCHIP_READ(W6100_Sn_DPORT0(s)+1)) & 0x00FF;
	return port;
}
#endif

/**
@brief	htons function converts a unsigned short from host to TCP/IP network byte order (which is big-endian).
@return 	the value in TCP/IP network byte order
*/
uint16_t htons(
    uint16_t hostshort /**< A 16-bit number in host byte order.  */
)
{
#if (SYSTEM_ENDIAN == _ENDIAN_LITTLE_)
  return swaps(hostshort);
#else
  return hostshort;
#endif
}

/**
@brief	htonl function converts a unsigned long from host to TCP/IP network byte order (which is big-endian).
@return 	the value in TCP/IP network byte order
*/
unsigned long htonl(
    unsigned long hostlong /**< hostshort  - A 32-bit number in host byte order.  */
)
{
#if (SYSTEM_ENDIAN == _ENDIAN_LITTLE_)
  return swapl(hostlong);
#else
  return hostlong;
#endif
}
/**
@brief	ntohs function converts a unsigned short from TCP/IP network byte order to host byte order (which is little-endian on Intel processors).
@return 	a 16-bit number in host byte order
*/
unsigned long ntohs(
    unsigned short netshort /**< netshort - network odering 16bit value */
)
{
#if (SYSTEM_ENDIAN == _ENDIAN_LITTLE_)
  return htons(netshort);
#else
  return netshort;
#endif
}

/**
@brief	converts a unsigned long from TCP/IP network byte order to host byte order (which is little-endian on Intel processors).
@return 	a 16-bit number in host byte order
*/
unsigned long ntohl(unsigned long netlong)
{
#if (SYSTEM_ENDIAN == _ENDIAN_LITTLE_)
  return htonl(netlong);
#else
  return netlong;
#endif
}

// destip : BigEndian
unsigned char CheckDestInLocal(unsigned long destip)
{
  int i = 0;
  unsigned char *pdestip = (unsigned char *)&destip;
  for (i = 0; i < 4; i++)
  {
    if ((pdestip[i] & WIZCHIP_READ(W6100_SUBR + i)) != (WIZCHIP_READ(W6100_SIPR + i) & WIZCHIP_READ(W6100_SUBR + i)))
      return 1; // Remote
  }
  return 0;
}

#include "device_resource.h"
void dhcp_set_network(void)
{
  uint8_t ip[4];
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    return;
  }
  setNETLCKR(0X3A); // Network Unlock before set Network Information
  // setSHAR(DHCP_GET.mac);/*配置Mac地址*/
  setSUBR(net_config->eth0_ipv4_netmask); /*配置子网掩码*/
  setGAR(net_config->eth0_ipv4_gw);       /*配置默认网关*/
  setSIPR(net_config->eth0_ipv4);         /*配置Ip地址*/
  setNETLCKR(0x00);
  //Init. TX & RX Memory size of w5100s
  // sysinit(0x55, 0x55); /*初始化4个socket*/
  setRTR(2000); /*设置溢出时间值*/
  setRCR(3);    /*设置最大重新发送次数*/
  LOG_INFO("DHCP result:\r\n");
  getSIPR(ip);
  LOG_INFO("IP : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  getSUBR(ip);
  LOG_INFO("SN : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  getGAR(ip);
  LOG_INFO("GW : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  xSemaphoreGive(w6100_op_xStaticMutex);
}

void Set_Network(void)
{
  uint8_t tmp_array[16];
  uint8_t txsize[8] = {2, 2, 2, 2, 2, 2, 2, 2};
  uint8_t rxsize[8] = {2, 2, 2, 2, 2, 2, 2, 2};
  uint8_t ip[4] = {0, 0, 0, 0};

#if 1
  if (xSemaphoreTake(w6100_op_xStaticMutex, portMAX_DELAY) != pdTRUE)
  {
    return;
  }
  setNETLCKR(0X3A); // Network Unlock before set Network Information
  //mac
  setSHAR(net_config->eth0_mac);

  // net mask
  memcpy(net_config->eth0_ipv4_netmask, setting_para->port1_IPV4_netmask, 4);
  setSUBR(net_config->eth0_ipv4_netmask); //
  //net gw
  memcpy(net_config->eth0_ipv4_gw, setting_para->port1_IPV4_GW, 4);
  setGAR(net_config->eth0_ipv4_gw);
  //net ipv4
  memcpy(net_config->eth0_ipv4, setting_para->port1_IPV4, 4);
  setSIPR(net_config->eth0_ipv4);

  memcpy(net_config->eth0_gw6, setting_para->port1_gw6, 16);
  setGA6R(net_config->eth0_gw6);

  memcpy(net_config->eth0_sn6, setting_para->port1_sn6, 16);
  setSUB6R(net_config->eth0_sn6);

  memcpy(net_config->eth0_lla, setting_para->port1_lla, 16);
  setLLAR(net_config->eth0_lla);

  memcpy(net_config->eth0_gua, setting_para->port1_gua, 16);
  setGUAR(net_config->eth0_gua);

  wizchip_init(txsize, rxsize);
  setRTR(2000);
  setRCR(5);
  getSIPR(ip);
  LOG_INFO("IP : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  getSUBR(ip);
  LOG_INFO("SN : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  getGAR(ip);
  LOG_INFO("GW : %d.%d.%d.%d\r\n", ip[0], ip[1], ip[2], ip[3]);
  setNETLCKR(0x00);
  getGA6R(tmp_array);
  LOG_INFO("GW6 : %04X:%04X", ((uint16_t)tmp_array[0] << 8) | ((uint16_t)tmp_array[1]),
           ((uint16_t)tmp_array[2] << 8) | ((uint16_t)tmp_array[3]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[4] << 8) | ((uint16_t)tmp_array[5]),
           ((uint16_t)tmp_array[6] << 8) | ((uint16_t)tmp_array[7]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[8] << 8) | ((uint16_t)tmp_array[9]),
           ((uint16_t)tmp_array[10] << 8) | ((uint16_t)tmp_array[11]));
  LOG_INFO(":%04X:%04X\r\n ", ((uint16_t)tmp_array[12] << 8) | ((uint16_t)tmp_array[13]),
           ((uint16_t)tmp_array[14] << 8) | ((uint16_t)tmp_array[15]));
  getLLAR(tmp_array);
  LOG_INFO("LLA : %04X:%04X", ((uint16_t)tmp_array[0] << 8) | ((uint16_t)tmp_array[1]),
           ((uint16_t)tmp_array[2] << 8) | ((uint16_t)tmp_array[3]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[4] << 8) | ((uint16_t)tmp_array[5]),
           ((uint16_t)tmp_array[6] << 8) | ((uint16_t)tmp_array[7]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[8] << 8) | ((uint16_t)tmp_array[9]),
           ((uint16_t)tmp_array[10] << 8) | ((uint16_t)tmp_array[11]));
  LOG_INFO(":%04X:%04X\r\n", ((uint16_t)tmp_array[12] << 8) | ((uint16_t)tmp_array[13]),
           ((uint16_t)tmp_array[14] << 8) | ((uint16_t)tmp_array[15]));
  getGUAR(tmp_array);
  LOG_INFO("GUA : %04X:%04X", ((uint16_t)tmp_array[0] << 8) | ((uint16_t)tmp_array[1]),
           ((uint16_t)tmp_array[2] << 8) | ((uint16_t)tmp_array[3]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[4] << 8) | ((uint16_t)tmp_array[5]),
           ((uint16_t)tmp_array[6] << 8) | ((uint16_t)tmp_array[7]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[8] << 8) | ((uint16_t)tmp_array[9]),
           ((uint16_t)tmp_array[10] << 8) | ((uint16_t)tmp_array[11]));
  LOG_INFO(":%04X:%04X\r\n", ((uint16_t)tmp_array[12] << 8) | ((uint16_t)tmp_array[13]),
           ((uint16_t)tmp_array[14] << 8) | ((uint16_t)tmp_array[15]));

  getSUB6R(tmp_array);
  LOG_INFO("SUB6 : %04X:%04X", ((uint16_t)tmp_array[0] << 8) | ((uint16_t)tmp_array[1]),
           ((uint16_t)tmp_array[2] << 8) | ((uint16_t)tmp_array[3]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[4] << 8) | ((uint16_t)tmp_array[5]),
           ((uint16_t)tmp_array[6] << 8) | ((uint16_t)tmp_array[7]));
  LOG_INFO(":%04X:%04X", ((uint16_t)tmp_array[8] << 8) | ((uint16_t)tmp_array[9]),
           ((uint16_t)tmp_array[10] << 8) | ((uint16_t)tmp_array[11]));
  LOG_INFO(":%04X:%04X\r\n", ((uint16_t)tmp_array[12] << 8) | ((uint16_t)tmp_array[13]),
           ((uint16_t)tmp_array[14] << 8) | ((uint16_t)tmp_array[15]));
  xSemaphoreGive(w6100_op_xStaticMutex);

#endif
}
